﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using CriptoHash.Connection;
using CriptoHash.Criptografia;
using CriptoHash.Model;

namespace CriptoHash.View
{
    public partial class AplicacaoServidor : Form
    {
        private TipoAplicacaoForm _pai;
        public TipoAplicacaoForm Pai
        {
            get { return _pai; }
            set { _pai = value; }
        }

        private Cliente _cliente;
        public Cliente Cliente
        {
            get { return _cliente; }
            set { _cliente = value; }
        }

        private Servidor _servidor;
        public Servidor Servidor
        {
            get { return _servidor; }
            set { _servidor = value; }
        }

        private Criptografador _criptografador;
        public Criptografador Criptografador
        {
            get { return _criptografador; }
            set { _criptografador = value; }
        }

        private Thread _threadReceberMensagens;
        public Thread ThreadReceberMensagens
        {
            get { return _threadReceberMensagens; }
            set { _threadReceberMensagens = value; }
        }

        public AplicacaoServidor(TipoAplicacaoForm Pai)
        {
            this.Pai = Pai;
            
            InitializeComponent();

            CheckForIllegalCrossThreadCalls = false;

            Criptografador = new Criptografador();

            ToLog("Servidor iniciado.");

            mudarCorPanel(false);
        }

        public AplicacaoServidor() : this(null) { }

        #region Close do Cliente para fechar a aplicação toda
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            if (Pai != null)
            {
                Pai.Close();
            }
        }
        #endregion

        #region Métodos da Thread de Receber Mensagens
        private void ThreadTask()
        {
            while (Servidor.Conectado)
            {
                //Dorme de 3 segundos em 3 segundos para verificar se chegaram mensagems
                Thread.Sleep(300);
                if (Servidor.mensagemDisponivel())
                {
                    if (MessageBox.Show("Mensagem recebida.") == DialogResult.OK)
                    {
                        LidarMensagemRecebida(Servidor.receberMensagemCertificado());
                    }
                }
            }
        }

        private void LidarMensagemRecebida(Mensagem mensagem)
        {
            string texto = mensagem.Texto;
            string certificado = mensagem.Hash;

            ToLog("Mensagem recebida: " + texto + "\r\nCertificado: " + certificado);

            txRecebido.Text = texto;
            txCertificadoRecebido.Text = certificado;

            string metodo = comboCertificado.SelectedItem.ToString();

            string gerado = Criptografador.ChamarMetodoHash(metodo, texto);

            ToLog("Certificado gerado: " + gerado);

            txGerado.Text = gerado;

            if (gerado.Equals(certificado))
            {
                ToLog("Certificados iguais. Mensagem recebida com sucesso!");
            }
            else
            {
                ToLog("Certificados diferentes. Mensagem recebida provavelmente foi alterada ou o método de certificação é diferente do esperado!");
            }
        }
        #endregion

        private void btnConectar_Click(object sender, EventArgs e)
        {
            string Ip = txServidorIp.Text;
            int Porta = int.Parse(txPorta.Text);

            if (null != Servidor && Servidor.Conectado)
            {
                ToLog("Servidor já está iniciado com: " + Servidor.Ip + ":" + Servidor.Porta + ". Desconectando...");
                Servidor.desconectar();
            }
            Servidor = new Servidor(Ip, Porta);
            bool conectado = Servidor.conectar();

            if (conectado)
            {
                ToLog("Servidor conectado com: " + Servidor.Ip + ":" + Servidor.Porta + ".");
                ThreadReceberMensagens = new Thread(new ThreadStart(this.ThreadTask));
                ThreadReceberMensagens.IsBackground = true;
                ThreadReceberMensagens.Start();
            }
            else
            {
                ToLog("Servidor não conseguiu subir.");
            }
            desbloquearComandos(conectado);
            mudarCorPanel(conectado);
        }

        private void btnDesconectar_Click(object sender, EventArgs e)
        {
            if (null != Servidor && Servidor.Conectado)
            {
                ToLog("Servidor está iniciado com: " + Servidor.Ip + ":" + Servidor.Porta + ". Desconectando...");
                Servidor.desconectar();

                bool conectado = Servidor.Conectado;

                desbloquearComandos(conectado);
                mudarCorPanel(conectado);
                if (!conectado)
                {
                    ThreadReceberMensagens.Abort();
                }
            }
        }

        private void btnGerar_Click(object sender, EventArgs e)
        {
            string metodo = comboCertificado.SelectedItem.ToString();

            string certificado = Criptografador.ChamarMetodoHash(metodo, txMensagem.Text);

            txCertificado.Text = certificado;
        }

        private void btnEnviar_Click(object sender, EventArgs e)
        {
            string texto = txMensagem.Text;

            btnGerar_Click(null, null);

            string certificado = txCertificado.Text;

            Mensagem mensagem = new Mensagem(texto, certificado);

            Servidor.enviarMensagem(mensagem);

            ToLog("Mensagem enviada: " + texto + "\r\nCertificado: " + certificado);
        }

        private void btnLimparEnviar_Click(object sender, EventArgs e)
        {
            txMensagem.Text = "";
        }

        private void btnLimparReceber_Click(object sender, EventArgs e)
        {
            txRecebido.Text = "";
        }

        private void desbloquearComandos(bool desbloquear)
        {
            btnConectar.Enabled = !desbloquear;
            btnDesconectar.Enabled = desbloquear;
            btnGerar.Enabled = desbloquear;
            btnEnviar.Enabled = desbloquear;
            btnLimparEnviar.Enabled = desbloquear;
            btnLimparReceber.Enabled = desbloquear;

            txMensagem.Enabled = desbloquear;
            txRecebido.Enabled = desbloquear;
            txGerado.Enabled = desbloquear;
            txCertificado.Enabled = desbloquear;
            txCertificadoRecebido.Enabled = desbloquear;

            comboCertificado.Enabled = desbloquear;

            if (desbloquear)
            {
                PreencherComboMetodos();
            }
        }

        private void ToLog(string message)
        {
            if (txLog.Text.Equals(""))
            {
                txLog.Text += message;
            }
            else
            {
                txLog.Text = message + "\r\n" + txLog.Text;
            }
        }

        private void mudarCorPanel(bool conectado)
        {
            if (conectado)
            {
                panelSinal.BackColor = Color.ForestGreen;
            }
            else
            {
                panelSinal.BackColor = Color.Firebrick;
            }
        }

        private void PreencherComboMetodos()
        {
            foreach (string metodo in Criptografador.ListaMetodos())
            {
                comboCertificado.Items.Add(metodo);
            }
            comboCertificado.SelectedIndex = 0;
        }
    }
}
